package dstree

import (
	"bytes"
	"crypto/sha256"
	"fmt"
)

// type MTree_Node struct {
// 	Lchild *MTree_Node
// 	Rchild *MTree_Node
// 	Parent *MTree_Node
// 	Digest []byte //哈希值
// }

type VO struct {
	Values []string
}

func (index *Dstree_Index) ads_construction(dsnode *Dstree_Node) []byte {
	// 叶节点
	if dsnode.Is_leaf {
		dsnode.Digest = Get_leafNode_hash(dsnode, *dsnode.data)
	} else {
		//非叶节点
		leftdigest := index.ads_construction(dsnode.Left_child)
		rightdigest := index.ads_construction(dsnode.Right_child)
		dsnode.Digest = Get_internalNode_hash(leftdigest, rightdigest, dsnode)
	}
	return dsnode.Digest
}

func Get_leafNode_hash(dsnode *Dstree_Node, data [][]Ts_type) []byte {

	//用二进制
	nodejson := Dstree_node_write_to_byte(dsnode)
	databyte := convertToBytes(data)
	data_value_hash := sha256.New()
	// data_value_hash.Write([]byte(datajson))
	data_value_hash.Write(databyte)

	datahash := data_value_hash.Sum(nil)
	// fmt.Printf("Get data node %s\n------------ data Digest=%+v\n", dsnode.Name, datahash)
	nodejson = append(nodejson, datahash...)
	value_hash := sha256.New()
	value_hash.Write([]byte(nodejson))
	return value_hash.Sum(nil)
}

func Get_internalNode_hash(left, right []byte, dsnode *Dstree_Node) []byte {
	nodejson := Dstree_node_write_to_byte(dsnode)
	value_hash := sha256.New()
	left = append(left, right...)
	left = append(left, nodejson...)
	value_hash.Write(left)
	return value_hash.Sum(nil)
}

func Get_node_data_digest(node *Dstree_Node) string {
	databyte := convertToBytes(*node.data)
	data_value_hash := sha256.New()
	// data_value_hash.Write([]byte(datajson))
	data_value_hash.Write([]byte(databyte))
	return string(data_value_hash.Sum(nil))
}

func Approximate_Knn_VO_Verify(given_results [][]Ts_type, query_ts []Ts_type, k int, vo VO, roothash []byte) bool {
	// fmt.Println("verifying approx knn vo")
	if len(given_results) != k {
		fmt.Printf("%d results are wanted but %d\n", k, len(given_results))
		return false
	}
	top := len(vo.Values) - 1
	leafNodeData := vo.Values[top]
	top--

	leafNodinfo := vo.Values[top]
	top--

	var childnode *Dstree_Node
	childnode = Dstree_node_read_from_byte([]byte(leafNodinfo))
	childnodedata := restoreFromString(leafNodeData, int(childnode.Node_Size), len(query_ts))
	NodeDigest := Get_leafNode_hash(childnode, childnodedata)

	var node *Dstree_Node
	is_left := childnode.Is_left
	for top != -1 { //栈不为空
		child1Digest := NodeDigest
		child2Digest := vo.Values[top]
		top--
		ParentNodeinfo := vo.Values[top]
		top--
		node = Dstree_node_read_from_byte([]byte(ParentNodeinfo))
		is_route_to_left := node.Node_split_policy_route_to_left(query_ts)

		if is_route_to_left != childnode.Is_left {
			return false
		}
		if is_left {
			NodeDigest = Get_internalNode_hash([]byte(child1Digest), []byte(child2Digest), node)
		} else {
			NodeDigest = Get_internalNode_hash([]byte(child2Digest), []byte(child1Digest), node)
		}
		// fmt.Printf("--------------Get internal Node %s\n-------------- Digest=%+v\n\n", node.Name, NodeDigest)
		childnode = node
		is_left = node.Is_left
	}

	if !bytes.Equal(NodeDigest, roothash) {
		return false
	}

	//验证计算节点内knn结果
	knn_results := make(PqItemSeries, k)
	for i := 0; i < k; i++ {
		knn_results[i] = Query_result{Node: nil, Distance: MaxtsType}
	}
	Calculate_ts_Set_knn_distance(childnodedata, query_ts, k, knn_results)

	//比对
	knn_ts := extract_knn_TS(knn_results)
	for i := 0; i < k; i++ {
		if !Result_is_equal(knn_ts[i], given_results[i]) {
			return false
		}
	}
	return true
}

func traverse_Verify_Exact_knn_search_vo(nodeinfo []byte, query_ts []Ts_type, k int, kth_result_distance Ts_type, knn_results PqItemSeries, top *int, vo []string) []byte {
	// fmt.Printf("Traverse_Verify_Exact_search_vo start\n")
	node, err := Load_nodeinfo(nodeinfo)
	if err != nil {
		fmt.Println("error:", err)
		return nil
	}

	var Left_child_digest, Right_child_digest []byte

	if node.Is_leaf { //此节点为叶节点,下一个值为data，需要计算确切的精确距离
		databyte := vo[*top]
		*top++
		data := restoreFromString(databyte, int(node.Node_Size), len(query_ts))
		Calculate_ts_Set_knn_distance(data, query_ts, k, knn_results)
		data_value_hash := sha256.New()
		data_value_hash.Write([]byte(databyte))

		nodejson := append([]byte(nodeinfo), data_value_hash.Sum(nil)...)
		leafnode_value_hash := sha256.New()
		leafnode_value_hash.Write([]byte(nodejson))

		return leafnode_value_hash.Sum(nil)

	} else {
		//selected internal node
		//检查孩子节点最小距离
		//左
		// fmt.Printf("               get node left child info top=%d\n", *top)
		var Left_child Dstree_Node
		Left_child_nodeinfo := []byte(vo[*top])
		*top++
		// fmt.Printf("               get node Load nodeinfo\n")
		Left_child, err = Load_nodeinfo(Left_child_nodeinfo)
		if err != nil {
			fmt.Println("error:", err)
			return nil
		}

		child_distance := Calculate_node_min_distance(&Left_child, query_ts)
		if child_distance < kth_result_distance {
			//继续遍历
			Left_child_digest = traverse_Verify_Exact_knn_search_vo(Left_child_nodeinfo, query_ts, k, kth_result_distance, knn_results, top, vo)
			// fmt.Printf("               Get %s 's left child %s 's digest \n", node.Name, Left_child.Name)
		} else {
			//pruned node
			if Left_child.Is_leaf {
				//pruned leaf node 下一个值为数据的哈希值
				Left_child_data_hash := vo[*top]
				*top++
				//计算叶节点哈希值 hash(nodeinfo,hash(nodedata))
				leafnodejson := append(Left_child_nodeinfo, []byte(Left_child_data_hash)...)
				value_hash := sha256.New()
				value_hash.Write([]byte(leafnodejson))
				// fmt.Printf("               compute left child %s 's digest \n", Left_child.Name)
				Left_child_digest = value_hash.Sum(nil)
			} else {
				//pruned internal node 后两个值为 其左右孩子的hash值
				Left_child_lchild_digest := []byte(vo[*top])
				*top++
				Left_child_rchild_digest := []byte(vo[*top])
				*top++
				//计算叶节点哈希值 hash(lchilddigest，rchilddigest，nodeinfo)
				Left_child_lchild_digest = append(Left_child_lchild_digest, Left_child_rchild_digest...)
				Left_child_lchild_digest = append(Left_child_lchild_digest, Left_child_nodeinfo...)
				value_hash := sha256.New()
				value_hash.Write([]byte(Left_child_lchild_digest))
				// fmt.Printf("               compute left child %s 's digest \n", Left_child.Name)
				Left_child_digest = value_hash.Sum(nil)
			}
		}
		//右
		var Right_child Dstree_Node
		Right_child_nodeinfo := []byte(vo[*top])
		*top++
		Right_child, err = Load_nodeinfo(Right_child_nodeinfo)
		// err = json.Unmarshal(Right_child_nodeinfo, &Right_child)
		if err != nil {
			fmt.Println("error:", err)
			return nil
		}
		child_distance = Calculate_node_min_distance(&Right_child, query_ts)
		if child_distance < kth_result_distance {
			//继续遍历
			Right_child_digest = traverse_Verify_Exact_knn_search_vo(Right_child_nodeinfo, query_ts, k, kth_result_distance, knn_results, top, vo)
			// fmt.Printf("               Get %s 's right child %s 's digest \n", node.Name, Right_child.Name)
		} else {
			//pruned node
			if Right_child.Is_leaf {
				//pruned leaf node 下一个值为数据的哈希值
				Right_child_data_hash := vo[*top]
				*top++
				//计算叶节点哈希值 hash(nodeinfo,hash(nodedata))
				leafnodejson := append(Right_child_nodeinfo, []byte(Right_child_data_hash)...)
				value_hash := sha256.New()
				value_hash.Write([]byte(leafnodejson))
				// fmt.Printf("               compute Right child %s 's digest \n", Right_child.Name)
				Right_child_digest = value_hash.Sum(nil)
			} else {
				//pruned internal node
				Right_child_lchild_digest := []byte(vo[*top])
				*top++
				Right_child_rchild_digest := []byte(vo[*top])
				*top++
				//计算叶节点哈希值 hash(lchilddigest，rchilddigest，nodeinfo)
				Right_child_lchild_digest = append(Right_child_lchild_digest, Right_child_rchild_digest...)
				Right_child_lchild_digest = append(Right_child_lchild_digest, Right_child_nodeinfo...)
				value_hash := sha256.New()
				value_hash.Write(Right_child_lchild_digest)
				// fmt.Printf("               compute Right child %s 's digest \n", Right_child.Name)
				Right_child_digest = value_hash.Sum(nil)
			}
		}
	}
	//计算自己digest并返回 hash(lchilddigest，rchilddigest，nodeinfo)
	// fmt.Printf("      compute node %s self digest \n", node.Name)
	value_hash := sha256.New()
	Left_child_digest = append(Left_child_digest, Right_child_digest...)
	Left_child_digest = append(Left_child_digest, nodeinfo...)
	value_hash.Write(Left_child_digest)

	self_digest := value_hash.Sum(nil)

	return self_digest
}

func PrintVOsize(vo VO) int {
	var vosize int
	for i := 0; i < len(vo.Values); i++ {
		// vosize += float64(unsafe.Sizeof(VO.items[i]))
		vosize += len(vo.Values[i])
	}
	return vosize
}

func Verify_Exact_knn_search_vo(query_ts []Ts_type, k int, given_results [][]Ts_type, resultvo []string, roothash []byte) bool {
	// fmt.Printf("Start to verify exact search vo\n")
	top := 0
	nodeinfo := []byte(resultvo[top])
	top++
	knn_results := make(PqItemSeries, k)
	for i := 0; i < k; i++ {
		knn_results[i] = Query_result{Node: nil, Distance: MaxtsType}
	}
	given_kth_distance := ts_euclidean_distance_reordered(given_results[k-1], query_ts)
	verifyhash := traverse_Verify_Exact_knn_search_vo(nodeinfo, query_ts, k, given_kth_distance, knn_results, &top, resultvo)

	fmt.Printf("verifyhash=%x\n,roothash=%x\n", verifyhash, roothash)
	if !bytes.Equal(verifyhash, roothash) {
		fmt.Printf("not root hash!")
		return false
	} else {
		//比对
		knn_ts := extract_knn_TS(knn_results)
		for i := 0; i < k; i++ {
			if !Result_is_equal(knn_ts[i], given_results[i]) {
				fmt.Printf("Results are wrong!")
				return false
			}
		}
		return true
	}
}
